#ifndef EXCHANGEAMX_H
#define EXCHANGEAMX_H

#include <unordered_map>
#include <vector>
#include <set>
#pragma once
#include "ExchangeBase.h"
#include "common/constant.h"

#ifdef AMXSTORAGE_ENABLE
#include "AmxStorage.h"
#include <DocumentInfo.h>
#endif


#include "nlohmann/json.hpp"
AMCAX_EXCHANGE_NAMESPACE_BEGIN

// NOTE: 对象ID的名称
static const std::string OBJECT_ITEM_FIELD_SORT_ID = "sortid";

// NOTE: 对象ID的名称
static const std::string OBJECT_ITEM_FIELD_ID = "dxid";

// NOTE: 对象的名称
static const std::string OBJECT_ITEM_FIELD_NAME = "label";

// NOTE: 对象的可见性
static const std::string OBJECT_ITEM_FIELD_VISIBILITY = "visibility";

// NOTE: 对象的名称
static const std::string OBJECT_ITEM_FIELD_TYPE = "type";

// NOTE:  对象的 Shape ID， 空则无模型(比如 容器，文字)
static const std::string OBJECT_ITEM_FIELD_SHAPE = "shape";

// NOTE: 对象的参数
static const std::string OBJECT_ITEM_FIELD_PARAMS = "params";

// NOTE: 对象的材质
static const std::string OBJECT_ITEM_FIELD_MATERIALS = "materials";

// NOTE: 坐标系，仅草图对象，可选
static const std::string OBJECT_ITEM_FIELD_FRAME = "frame";

// NOTE: 标记是否为负实体，可选
static const std::string OBJECT_ITEM_FIELD_NEGATIVE = "negative";

// NOTE: 可选, ID追踪信息
static const std::string OBJECT_ITEM_FIELD_TRACK = "track";

// NOTE: 用户自定义标签
static const std::string OBJECT_ITEM_FIELD_MARK = "mark";

// NOTE: 子对象
static const std::string OBJECT_ITEM_FIELD_CHILDREN = "children";

// NOTE: 特征操作用的，如圆角基于那个方块做的 ，则base_id为该方块的id
static const std::string OBJECT_ITEM_FIELD_BASEID = "baseid";

// NOTE: CAD特征的关联关系，圆角特征是从方块创建的。prelink指向方块的信息。这个特征生成可能依赖多个特征
// NOTE: 参数化建模，每一步都要重建，所以依赖这个,用于重建 -> 利用有向无环图
static const std::string OBJECT_ITEM_FIELD_PRE_LINKS = "prelinks";

// NOTE: 某个特征被那些特征依赖过
// NOTE: 参数化建模，每一步都要重建，所以依赖这个,用于重建 -> 利用有向无环图
static const std::string OBJECT_ITEM_FIELD_OUT_LINKS = "outlinks";

static const std::string MATERIALS_ITEM_FIELD_FACES = "faces";
static const std::string MATERIALS_FACE_ITEM_FIELD_FACEID = "index";
static const std::string MATERIALS_FACE_ITEM_FIELD_MATID_IN_DB = "mat";

static const std::string MATERIAL_ITEM_IN_DATABSE_FIELD_NAME = "name";
static const std::string MATERIAL_ITEM_IN_DATABSE_FIELD_COLOR = "color";
static const std::string MATERIAL_ITEM_IN_DATABSE_FIELD_AMBIENT = "ambient";
static const std::string MATERIAL_ITEM_IN_DATABSE_FIELD_DIFFUSE = "diffuse";
static const std::string MATERIAL_ITEM_IN_DATABSE_FIELD_EMISSIVE = "emissuse";
static const std::string MATERIAL_ITEM_IN_DATABSE_FIELD_SPECULAR = "specular";
static const std::string MATERIAL_ITEM_IN_DATABSE_FIELD_SHININESS = "shininess";
static const std::string MATERIAL_ITEM_IN_DATABSE_FIELD_TRANSPARENCY = "transparency";
static const std::string MATERIAL_ITEM_IN_DATABSE_FIELD_TEXTTURE = "texture";
static const std::string MATERIAL_ITEM_IN_DATABSE_FIELD_ID = "id";

class ExchangeDocumentInstance;
class ExchangeDocumentReference;

class ExchangeAmx : public ExchangeBase
{
public:
    ExchangeAmx(std::string file_path) : ExchangeBase(file_path) {};
    ExchangeAmx(std::shared_ptr<std::fstream> in_file_stream,std::shared_ptr<std::fstream> out_file_stream)
        : ExchangeBase(in_file_stream, out_file_stream, EXCHANGE_FILE_TYPE::AMX) {};
        
    void ReadFromFilePath() override;
    void ReadFromFileStream() override;
    void Write(const std::vector<std::shared_ptr<ExchangeObject>> &exchange_shapes, const std::shared_ptr<ExchangeDocumentInstance> &exchangeRootDocumentInstance) override;
#ifdef AMXSTORAGE_ENABLE
    void read_common(const std::shared_ptr<AMCAX::STORAGE::AmxStorage> amx_storage);
    void parse_object_list(const std::shared_ptr<AMCAX::STORAGE::AmxStorage> amx_storage,
                           const std::string document_id,
                           const std::string document_version,
                           const std::string str_object_info);
    std::shared_ptr<ExchangeObject> parse_object_item_recursion(
        const std::shared_ptr<AMCAX::STORAGE::AmxStorage> amx_storage,
        const std::string document_id,
        const std::string document_version,
        const nlohmann::json &json_item,
        const nlohmann::json &json_materials_in_database,
        std::string prefix);
    // void parse_object_item(nlohmann::json &json_item) ;
    

    using json = nlohmann::json;
    // void ExchangeAmx::write_common(const std::vector<std::shared_ptr<ExchangeObject>> &exchange_shapes,
    //                                const std::shared_ptr<AMCAX::STORAGE::AmxStorage> amx_storage);
    json write_object_item_recursion(const std::shared_ptr<ExchangeObject> &exchange_shape,
                                     const std::shared_ptr<AMCAX::STORAGE::AmxStorage> &amx_storage,
                                     const std::string &document_id, const std::string &document_version,
                                     nlohmann::json &json_materials_in_database);

    AMCAX::STORAGE::DocumentRefInfo writeDocumentInstanceRecursion(std::shared_ptr<AMCAX::STORAGE::AmxStorage> &amx_storage,
                                                                   const std::shared_ptr<ExchangeDocumentInstance> &exchangeDocumentInstance, bool isRoot = false);

    AMCAX::STORAGE::DocumentRefInfo writeAmxByDocumentReference(std::shared_ptr<AMCAX::STORAGE::AmxStorage> &amx_storage,
        const std::shared_ptr<ExchangeDocumentReference> &exchangeDocumentReference, bool isRoot);
#endif
private:

#ifdef AMXSTORAGE_ENABLE
    void childInstancesToJson(const std::vector<std::shared_ptr<ExchangeDocumentInstance>>& childInstances, nlohmann::json& arr);
    std::unordered_map<int, AMCAX::STORAGE::DocumentRefInfo> exchangeDocumentIdMap_;
    std::vector<std::pair<std::string, std::string>> parents_;
    std::set<std::pair<std::string, std::string>> docRelations_;
#endif
};
AMCAX_EXCHANGE_NAMESPACE_END
#endif